#pragma once
#include "Math.h"
#include <d3dx9math.h>

class Vector3
{
public:

	float x, y, z;

	Vector3(){}

	Vector3(const Vector3 &a) : x(a.x), y(a.y), z(a.z) {}

	Vector3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}


	// Operators

	Vector3 &operator =(const Vector3 &a)
	{
		x = a.x; y = a.y; z = a.z;
		return *this;
	}

	bool operator ==(const Vector3 &a) const
	{
		return x == a.x && y == a.y && z == a.z;
	}

	bool operator !=(const Vector3 &a) const
	{
		return x != a.x || y != a.y || z != a.z;
	}

	void zero() { x = y = z = 0; }

	Vector3 operator -() const
	{
		return Vector3(-x, -y, -z);
	}

	Vector3 operator +(const Vector3 &a) const
	{
		return Vector3(x + a.x, y + a.y, z + a.z);
	}

	Vector3 operator -(const Vector3 &a) const
	{
		return Vector3(x - a.x, y - a.y, z - a.z);
	}

	Vector3 operator *(float a) const
	{
		return Vector3(x * a, y * a, z * a);
	}

	Vector3 operator /(float a) const
	{
		if (a > 0)
		{
			float oneOnA = 1 / a;
			return Vector3(x * oneOnA, y * oneOnA, z * oneOnA);
		} else {
			return Vector3(x, y, z);
		}
	}

	Vector3 &operator +=(const Vector3 &a)
	{
		x += a.x; y += a.y; z += a.z;
		return *this;
	}

	Vector3 &operator -=(const Vector3 &a)
	{
		x -= a.x; y -= a.y; z -= a.z;
		return *this;
	}

	Vector3 &operator *=(float a)
	{
		x *= a; y *= a; z *= a;
		return *this;
	}

	Vector3 &operator /=(float a)
	{
		if (a > 0)
		{
			float oneOnA = 1 / a;
			x *= oneOnA; y *= oneOnA; z *= oneOnA;
			return *this;
		} else {
			return *this;
		}
	}

	float operator *(const Vector3 &a) const
	{
		return x * a.x + y * a.y + z * a.z;
	}

};


inline float VectorMagnitude(const Vector3 &a)
{
	return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
}

inline Vector3 CrossProduct(const Vector3 &a, const Vector3 &b)
{
	return Vector3(
		a.y * b.z - b.y * a.z,
		a.x * b.z - b.x * a.z,
		a.x * b.y - b.x * a.y
		);
}

inline Vector3 operator *(float k, const Vector3 &v)
{
	return Vector3(k * v.x, k * v.y, k * v.z);
}

inline float Distance(const Vector3 &a, const Vector3 &b)
{
	float dx = a.x - b.x;
	float dy = a.y - b.y;
	float dz = a.z - b.z;
	return sqrt(dx * dx + dy * dy + dz*dz);
}

inline Vector3 Normalise(const Vector3 &a)
{
	float magSq = a.x * a.x + a.y * a.y + a.z * a.z;
	if(magSq > 0)
	{
		float oneOnMag = 1 / sqrt(magSq);
		
		return Vector3(a.x * oneOnMag, a.y * oneOnMag, a.z * oneOnMag);
	}
	return a;
}

inline float DotProduct(const Vector3 &a, const Vector3 &b)
{
	return a.x * b.x + a.y * b.y + a.z * b.z;
}

inline float Angle(const Vector3 &a, const Vector3 &b)
{
	return D3DXToDegree(acos(DotProduct(a, b) / (VectorMagnitude(a) * VectorMagnitude(b))));
}

inline Vector3 YawPitchRoll(const Vector3 &a, const Vector3 &b)
{
	Vector3 returnVec(0, 0, 0), tempVec(0, 0, 0);
	
	tempVec = Vector3(0, a.y, a.z);
	returnVec.x = Angle(tempVec, b);
	tempVec = Vector3(a.x, 0, a.z);
	returnVec.y = Angle(tempVec, b);
	tempVec = Vector3(a.x, a.y, 0);
	returnVec.z = Angle(tempVec, b);

	return returnVec;
}